package com.dkts.oil.router.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.dkts.oil.converter.GeometryConverter;
import com.dkts.oil.exception.OilException;
import com.dkts.oil.model.GHPoint;
import com.dkts.oil.router.TransportRoute;
import com.dkts.oil.router.param.PathInfo;
import com.dkts.oil.router.param.RouterInfo;
import com.dkts.oil.service.impl.OilAddressV2Helper;
import com.dkts.oil.util.TrackMileageUtil;
import com.dkts.oil.web.vo.request.RouteCommonRequest;
import lombok.extern.slf4j.Slf4j;
import org.locationtech.jts.geom.Geometry;

import java.util.ArrayList;
import java.util.List;

/**
 * 公共的帮助类，用于实现路由规划的公共功能
 */
@Slf4j
public class RouterCommonHelper {

    private JSONObject defaultParam = JSONObject.parseObject("{\"points\":[[103.03256796874994,29.782996334195047],[116.747283,27.638004]],\"profile\":\"truck\",\"elevation\":true,\"instructions\":true,\"locale\":\"zh_CN\",\"points_encoded\":false,\"points_encoded_multiplier\":1000000,\"details\":[\"road_class\",\"road_environment\",\"max_speed\",\"average_speed\"],\"snap_preventions\":[\"ferry\"],\"alternative_route.max_paths\":3,\"algorithm\":\"alternative_route\"}");

    public JSONObject getRouteParam(List<GHPoint> points, String type) {
        JSONObject jsonObjectTemp = (JSONObject) defaultParam.clone();
        JSONArray pointsTemp = new JSONArray();
        for (GHPoint point : points) {
            JSONArray pointTemp = new JSONArray();
            pointTemp.add(point.getLon());
            pointTemp.add(point.getLat());
            pointsTemp.add(pointTemp);
        }
        jsonObjectTemp.put("points", pointsTemp);
        jsonObjectTemp.put("profile", type);
        return jsonObjectTemp;
    }

    public Geometry check(RouteCommonRequest param, TransportRoute routeType){
        if (param.getPointGeoJson() == null){
            throw new OilException(routeType.getName()+",机场边界必传");
        }
        Geometry geometry=null;
        try{
            JSONObject jsonObject = JSONObject.parseObject(param.getPointGeoJson());
            geometry= GeometryConverter.geoJsonToGeometry(jsonObject.getJSONObject("geometry").toJSONString());
        }catch (Exception e){
            log.error("{}机场边界geojson格式错误", routeType.getName(), e);
            throw new OilException(routeType.getName()+",机场边界geojson格式错误");
        }

        GHPoint airPoint=param.airportDoorPoint;
        if (airPoint==null){
            throw new OilException("储备库到消耗库，机场大门坐标不能为空");
        }
        return geometry;
    }

    // 解析整个 paths 数组
    public static RouterInfo parseAllRouteSegments(JSONArray pathsArray, String routerModel, Integer type,Double  distance,int  segment,Double localRoute) {


        List<PathInfo> allSegments = new ArrayList<>();

        for (int i = 0; i < pathsArray.size(); i++) {
            JSONObject pathObj = pathsArray.getJSONObject(i);
            PathInfo segments = parseRouteSegments(pathObj);
            segments.setFundInfo(OilAddressV2Helper.summarizeInstructions(segments.getInstructions()));
            //判断是否需要创建的公路
            setNewRoadData(segments,distance,segment,localRoute);
            allSegments.add(segments);
        }
        return new RouterInfo(allSegments, routerModel, type);
    }

    private static void setNewRoadData(PathInfo segments,Double  distance,int segment,Double localRoute) {
        JSONArray coordinates =segments.getPoints().getCoordinates();
        ArrayList<PathInfo.RoutePoints> pointsNew = new ArrayList<>();

        int row = coordinates.size();
        PathInfo.RoutePoints pointsStart = setNewRoaderData(coordinates.getJSONArray(0), coordinates.getJSONArray(1), segments,1,distance,segment,localRoute);
        int i=0;
        int endJ=row;
        if (pointsStart != null){
            i=1;
            pointsNew.add(pointsStart);
        }

        PathInfo.RoutePoints pointsEnd = setNewRoaderData(coordinates.getJSONArray(row - 2), coordinates.getJSONArray(row - 1), segments,2,distance,segment,localRoute);

        if (pointsEnd != null){
            endJ=row-1;
        }
        JSONArray coordinatesMid = new JSONArray();
        for (int j = i; j < endJ; j++) {
            coordinatesMid.add(coordinates.get(j));
        }
        pointsNew.add(new PathInfo.RoutePoints(coordinatesMid));
        if (pointsEnd != null){
            pointsNew.add(pointsEnd);
        }
        segments.setPoints(null);
        segments.setRoadInfos(pointsNew);
    }

    private static PathInfo.RoutePoints setNewRoaderData(JSONArray coordinates0, JSONArray coordinates1,PathInfo segments,int index,Double  isNewDistance,int segment,Double localRoute) {

        //明确不需要分段
        if (segment == 1){
            return null;
        }

        //需要分段
        if (segment==2) {
            return setNewRoaderData(coordinates0,coordinates1,segments,index,isNewDistance,localRoute);
        }
        //若XHK在机场外部，需规划第一、二、三段
        //第一段：CBK——>最佳点A（已有公路上）【新增路线】
        //第二段：最佳点A（已有公路上）——>最佳点B（已有公路上）【已有路线】
        //第三段：最佳点B（已有公路上）——>XHK【新增路线】
        //若XHK在机场内部，需规划第一、二、三段（如果是内部只规划到机场大门的路线，在机场设计条件增加大门的位置坐标）
        //第一段：CBK——>最佳点A（已有公路上）【新增路线】
        //第二段：最佳点A（已有公路上）——>最佳点B（已有公路上）【已有路线】
        //第三段：最佳点B（已有公路上）——>机场大门【新增路线】
        if (segment==3) {

            return null;
        }
//        XHK到WCGY中心规划逻辑：
//        若XHK在机场外部，需规划第一、二、三段
//        第一段：最佳点A（CBK到XHK的公路终点）——>最佳点B（已有公路上）【新增路线】
//        第二段：最佳点B（已有公路上）——>最佳点C（已有公路上）【已有路线】
//        第三段：最佳点C（已有公路上）——>机场大门【新增路线】
//        若XHK在机场内部，终止规划
        if (segment==4){

            return null;
        }
        return null;
    }

    // 解析单个 path 对象
    public static PathInfo parseRouteSegments(JSONObject pathObj) {
        return pathObj.toJavaObject(PathInfo.class);
    }
    public static PathInfo.RoutePoints setNewRoaderData(JSONArray coordinates0, JSONArray coordinates1, PathInfo segments, int index, Double isNewDistance,Double localRoute) {
        PathInfo.RoutePoints pointsNew = null;
        if (isNewDistance == null) {
            isNewDistance = 5000D;
        }
        //计算连点之间的距离大于5公里的
        double distance = TrackMileageUtil.distance(coordinates0.getDouble(1), coordinates0.getDouble(0), coordinates1.getDouble(1), coordinates1.getDouble(0));
        if (distance > isNewDistance) {
            pointsNew = new PathInfo.RoutePoints();
            pointsNew.setRoadType(1);
            pointsNew.setCoordinates(RouterLocalHelper.router(coordinates0,coordinates1, localRoute));
        }

        if (pointsNew != null && index == 1) {
            segments.setStartNewRoad(new PathInfo.CreateRoadSegments(distance, true));
        } else if (pointsNew != null && index == 2) {
            segments.setEndNewRoad(new PathInfo.CreateRoadSegments(distance, true));
        }
        return pointsNew;
    }

    public static PathInfo.CreateRoadSegments createRoadSegmentsDist(JSONArray coordinates0, JSONArray coordinates1) {
        double distance = TrackMileageUtil.distance(coordinates0.getDouble(1), coordinates0.getDouble(0), coordinates1.getDouble(1), coordinates1.getDouble(0));
        return new PathInfo.CreateRoadSegments(distance, true);
    }

    public RouterInfo routerEndSegments(JSONArray pathsArray, String routerModel, Integer type, Double distance,Double localRoute) {
        List<PathInfo> allSegments = new ArrayList<>();
        for (int i = 0; i < pathsArray.size(); i++) {
            JSONObject pathObj = pathsArray.getJSONObject(i);
            PathInfo segments = parseRouteSegments(pathObj);
            segments.setFundInfo(OilAddressV2Helper.summarizeInstructions(segments.getInstructions()));
            //判断是否需要创建的公路
            setEndRoadData(segments, distance, localRoute);
            allSegments.add(segments);
        }
        return new RouterInfo(allSegments, routerModel, type);
    }

    /**
     * 1.炼油厂到ZYZ规划逻辑：
     * 若规划铁路，只需规划第二、三段
     * 第一段：炼油厂——>火车站（距离炼油厂最近）【新增路线】 - 这个不需要规划，如果没有铁路线就找最近的火车站
     * 第二段：火车站（距离炼油厂最近）——>火车站（距离ZYZ最近）【已有路线】
     * 第三段：火车站（距离ZYZ最近）——>ZYZ【新增路线】
     * 若规划水路，只需规划第二段
     * 第一段：炼油厂——>港口/码头（距离炼油厂最近）【新增路线】-这个不需要规划
     * 第二段：港口/码头（距离炼油厂最近）——>港口/码头（距离ZYZ最近）【已有路线，沿着长江或者珠江即可】
     * 第三段：港口/码头（距离ZYZ最近）——>ZYZ【新增路线】-这个不需要规划
     *
     * @param segments
     * @param distance
     */
    public void setEndRoadData(PathInfo segments, Double distance,Double localRoute) {
        JSONArray coordinates = segments.getPoints().getCoordinates();
        ArrayList<PathInfo.RoutePoints> pointsNew = new ArrayList<>();

        int row = coordinates.size();

        PathInfo.RoutePoints pointsEnd = setNewRoaderData(coordinates.getJSONArray(row - 2), coordinates.getJSONArray(row - 1), segments, 2, distance,localRoute);
        int endJ = pointsEnd == null ? row : row - 1;
        JSONArray coordinatesMid = new JSONArray();
        for (int j = 0; j < endJ; j++) {
            coordinatesMid.add(coordinates.get(j));
        }
        pointsNew.add(new PathInfo.RoutePoints(coordinatesMid));
        if (pointsEnd != null) {
            pointsNew.add(pointsEnd);
        }
        segments.setPoints(null);
        segments.setRoadInfos(pointsNew);
    }
}